/**
 * @desc 事件触发与事件监听器  http://nodejs.cn/api/events.html#class-eventemitter
 */ 
class EventEmitter {
  constructor() {
    this._maxListeners = 20;
    this._events = {};
  }
  setMaxListeners(n) {
    this._maxListeners = typeof n == "number" && n > 0 ? parseInt(n) : this._maxListeners;
  }
  emit(...args) {
    const type = args[0];
    if (type === "error") {
      if (!this._events.error || (isArray(this._events.error) && !this._events.error.length)) {
        if (args[1] instanceof Error) throw args[1]; // Unhandled 'error' event
        else throw new Error("Uncaught, unspecified 'error' event.");
        return false;
      }
    }
    const handler = this._events[type];
    if (Array.isArray(handler) && handler.length) {
      let listeners = handler.slice();
      for (let e of listeners) e.apply(this, args.slice(1));
      return true;
    }
    return false;
  }
  addListener(type, listener) {
    if ("function" !== typeof listener) throw new Error("addListener only takes instances of Function");
    // 触发 新增 事件
    this.emit("newListener", type, listener);
    if (!this._events[type]) this._events[type] = [listener];
    else this._events[type].push(listener);
    if (!this._events[type].warned) {
      if (this._events[type].length > this._maxListeners) {
        this._events[type].warned = true; //警告标识
        console.error("Possible mem-leak detected. event[" + type + "] %d listeners added. " + "Use emitter.setMaxListeners() to increase limit.", this._events[type].length);
        console.trace();
      }
    }
    return this;
  }
  on(type, listener) {
    return this.addListener(type, listener);
  }
  once(type, listener) {
    if ("function" !== typeof listener) throw new Error(".once only takes instances of Function");
    var self = this;
    function g() {
      self.removeListener(type, g);
      listener.apply(this, arguments);
    }
    this.on(type, g);
    return this;
  }
  listeners() {
    if (!this._events) this._events = {};
    if (!this._events[type]) this._events[type] = [];
    if (!isArray(this._events[type])) this._events[type] = [this._events[type]];
    return this._events[type];
  }
  removeListener(type, listener) {
    if ("function" !== typeof listener) throw new Error("removeListener only takes instances of Function");
    if (!this._events[type]) return this;
    this._events[type] = this._events[type].filter((v) => v !== listener);
    return this;
  }
  removeAllListeners(...args) {
    if (args.length === 0) {
      this._events = {};
      return this;
    }
    if (this._events[args[0]]) delete this._events[args[0]];
    return this;
  }
}

export default EventEmitter;
